package com.bear.richtext

import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.KeyEvent
import android.view.MotionEvent
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.LinearLayout
import android.widget.ScrollView
import androidx.core.view.children
import androidx.core.view.isVisible
import com.bear.richtext.type.*
import com.bear.richtext.utils.*
import org.json.JSONArray

class RichText(context: Context, attrs: AttributeSet?, defStyleAttr: Int) :
    ScrollView(context, attrs, defStyleAttr) {

    companion object {
        private val TAG = "RichText"
    }

    constructor(context: Context) : this(context, null, 0)
    constructor(context: Context, attributeSet: AttributeSet) : this(context, attributeSet, 0)

    /**所有子view的容器 */
    private lateinit var layout: LinearLayout

    private lateinit var mKeyListener: OnKeyListener
    private lateinit var mFocusListener: OnFocusChangeListener
    private var lastFocusEdit: EditText? = null

    private var isEditable = true //是否可编辑

    init {
        initLayoutView()
        initListener()
        initFirstEditText()
    }

    override fun onVisibilityChanged(changedView: View, visibility: Int) {
        super.onVisibilityChanged(changedView, visibility)

        Log.i(TAG, "onvisiblechange:visibility:${visibility}")
        if (visibility == View.VISIBLE) {
            Tools.report(Constant.Event.EXPOSURE, mapOf())
        } else {
            Tools.report(Constant.Event.UNEXPOSURE, mapOf())
        }
    }

    var motionEvent:MotionEvent? = null

    private fun initLayoutView() {
        layout = LinearLayout(context)
        layout.orientation = LinearLayout.VERTICAL
        val layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
        addView(layout, layoutParams)
        layout.setOnClickListener {
            //找到最近的EditText，将焦点给它
            motionEvent?.let { event ->
                layout.children.forEach {
                    if (it.isVisible) {
                        val location = IntArray(2)
                        it.getLocationOnScreen(location)
                        val top = location[1]
                        val bottom = top + it.height
                        val y = event.rawY
                        if (y >= top && y <= bottom) {
                            if (it is EditText) {
                                it.requestFocus()
                                it.setSelection(it.text.length)
                            }
                            return@forEach
                        }
                    }
                }
            }
        }
        layout.setOnTouchListener(object : OnTouchListener {
            override fun onTouch(p0: View?, p1: MotionEvent?): Boolean {
                motionEvent = p1
                return false
            }
        })
    }

    private fun initListener() {
        mKeyListener = object : OnKeyListener {
            override fun onKey(view: View?, p1: Int, keyEvent: KeyEvent?): Boolean {
                keyEvent?.let {
                    if (it.action == KeyEvent.ACTION_DOWN && it.keyCode == KeyEvent.KEYCODE_DEL && view is EditText) {
                        onBackspacePress(view)
                    }
                }
                return false
            }
        }

        mFocusListener = object : OnFocusChangeListener {
            override fun onFocusChange(view: View?, hasFocus: Boolean) {
                view?.let {
                    if (hasFocus) {
                        lastFocusEdit = it as EditText
                    }
                }
            }
        }
    }

    private fun onBackspacePress(editText: EditText) {
        val startSelection = editText.selectionStart
        if (startSelection == 0) {
            val editIndex = layout.indexOfChild(editText)
            val preView = layout.getChildAt(editIndex - 1)
            preView?.let {
                when (preView) {
                    is EditText -> {
                        if (editText.text.length == 0) {
                            layout.removeView(editText)
                        }
                        (it as EditText).apply {
                            requestFocus()
                            setSelection(text.length)
                        }
                    }
                    else -> {
                        layout.removeView(preView)
                    }
                }
            }
        }
    }

    private fun initFirstEditText() {
        val editParams =
            LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
        val editText = createEditText()
        layout?.addView(editText, editParams)
        lastFocusEdit = editText
    }

    private fun createEditText(): EditText {
        val richItem = ItemText(context)
        (richItem.getView() as EditText).apply {
            this.setOnKeyListener(mKeyListener)
            this.onFocusChangeListener = mFocusListener
            this.setTag(richItem)
        }
        return richItem.getView() as EditText
    }

    fun insertRichItem(item: RichItem) {
        if (!isEditable) {
            Tools.elog(TAG, "can not edit")
            return
        }
        val lastEditStr = lastFocusEdit!!.text.toString()
        val cusorIndex = lastFocusEdit!!.selectionStart
        val editStrPre = lastEditStr.substring(0, cusorIndex).trim()
        val editStrAfter = lastEditStr.substring(cusorIndex).trim()
        val lastEditIndex = layout.indexOfChild(lastFocusEdit)
        if (editStrPre.isEmpty() && editStrAfter.isEmpty()) {
            layout.addView(item.getView(), lastEditIndex)
        } else if (editStrAfter.isEmpty()) {
            addEditTextAtIndex(lastEditIndex + 1, "")
            layout.addView(item.getView(), lastEditIndex + 1)
        } else {
            lastFocusEdit!!.setText(editStrPre)
            addEditTextAtIndex(lastEditIndex + 1, editStrAfter)
            layout.addView(item.getView(), lastEditIndex + 1)
        }
        if (item.getView() is EditText) {
            item.getView()?.apply {
                this.setOnKeyListener(mKeyListener)
                this.onFocusChangeListener = mFocusListener
            }
        }
        item.getView()?.setTag(item)
        hideKeyBoard()
    }

    fun insertImg(imagePath: String) {
        val richItem = ItemImage(context, imagePath)
        insertRichItem(richItem)
    }

    fun insertTag(content: String, color: String = "#FF0000") {
        val tagItem = ItemTag(context, content, color)
        insertRichItem(tagItem)
    }

    fun save(): JSONArray {
        val jsonarray = JSONArray()
        layout.children.forEach {
            val richItem = it.getTag()
            if (richItem != null && richItem is RichItem) {
                jsonarray.put(richItem.toJson())
            }
        }
        return jsonarray
    }

    private fun addEditTextAtIndex(index: Int, editStr: String) {
        val editText = createEditText()
        if (editStr.isNotEmpty()) {
            editText.setText(editStr)
        }
        layout.addView(editText, index)
        lastFocusEdit = editText
        lastFocusEdit!!.requestFocus()
        lastFocusEdit!!.setSelection(editStr.length, editStr.length)
    }

    private fun hideKeyBoard() {
        val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
        if (imm != null && lastFocusEdit != null) {
            imm.hideSoftInputFromWindow(lastFocusEdit!!.windowToken, 0)
        }
    }

    fun setEditable(editable: Boolean) {
        this.isEditable = editable
        layout.children.forEach {
            val richItem = it.getTag()
            if (richItem != null && richItem is RichItem) {
                richItem.setEditable(editable)
            }
        }
    }

    fun getEditable(): Boolean {
        return this.isEditable
    }

    fun parse(item: RichItem, clickListener: View.OnClickListener? = null) {
        clickListener?.let {
            item.getView()?.setOnClickListener { view ->
                clickListener.onClick(view)
            }
        }
        layout.addView(item.getView())
    }

    @OptIn(ExperimentalStdlibApi::class)
    fun parse(jsonArray: JSONArray) {
        uiThread {
            try {
                layout.removeAllViews()
                val size = jsonArray.length()
                for (i in 0 until size) {
                    val jsonObject = jsonArray.optJSONObject(i)
                    val type = jsonObject.optString(RichItem.TYPE, "")
                    val item = when (type) {
                        RichItemType.Tag.name -> ItemTag(context, jsonObject)
                        RichItemType.Gif.name -> ItemGif(context, jsonObject)
                        RichItemType.Image.name -> ItemImage(context, jsonObject)
                        RichItemType.Text.name -> ItemText(context, jsonObject)
                        RichItemType.Clickable.name -> ItemClickable(context, jsonObject)
                        RichItemType.NewLine.name -> ItemNewLine(context, jsonObject)
                        else -> null
                    }
                    item?.let {
                        it.getView()?.setTag(it)
                        layout.addView(item.getView())
                    }
                    if (item?.getView() is EditText) {
                        item.getView()?.apply {
                            setOnKeyListener(mKeyListener)
                            onFocusChangeListener = mFocusListener
                        }
                    }
                }
                initFirstEditText()
            } catch (e: Exception) {
                Tools.elog(TAG, "parse json error,json:${jsonArray},error:${e}")
                Tools.report(Constant.Event.PARSE_ITEM_ERROR, buildMap {
                    put("error", e.toString())
                    put("jsonArray", jsonArray.toString())
                })
            }
        }
    }

    //设置外部日志接口
    fun setLogInterface(iLog: IRichTextLog) {
        Tools.setLogInterface(iLog)
    }

    //设置外部图片加载接口
    fun setImgLoader(iLoadImg: ILoadImg) {
        Tools.setImgLoadInterface(iLoadImg)
    }

    //设置上报接口
    fun setReporter(report: IReport) {
        Tools.setReport(report)
    }
}